package cn.js.sangu.unitStore.controller;

import java.io.IOException;
import java.net.URLEncoder;
import java.sql.BatchUpdateException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.js.sangu.unitStore.common.LogType;
import cn.js.sangu.unitStore.common.MyAuthAccess;
import cn.js.sangu.unitStore.common.MyLogsAOP;
import cn.js.sangu.unitStore.common.R;
import cn.js.sangu.unitStore.common.exception.ServiceException;
import cn.js.sangu.unitStore.dto.ResetPwdDTO;
import cn.js.sangu.unitStore.dto.TreeDataDTO;
import cn.js.sangu.unitStore.dto.UserDTO;
import cn.js.sangu.unitStore.entity.User;
import cn.js.sangu.unitStore.service.FileService;
import cn.js.sangu.unitStore.service.UserService;
import lombok.extern.slf4j.Slf4j;

/**
 * 说明：
 * 作者：linshuo
 * 日期：2024/8/7 8:40
 */
//@CrossOrigin //已有全局跨域设置CorsConfig
@RequestMapping("user")
@RestController
@Slf4j
public class UserController {

    static final String OPERATION_USER = "用户模块";

    UserService userService;

    //正确的通过set方法注入对象的方式
    @Autowired
    public void setUserService(UserService userService){
        this.userService = userService;
    }

    @Autowired
    FileService fileService;

    @MyLogsAOP(operation = OPERATION_USER,operaType = LogType.ADD)
    @RequestMapping("save")
    public R save(@RequestBody UserDTO dto){
        User user = userService.save(dto);
        return R.ok(user.getUsername()+"用户保存成功");
    }

    @MyLogsAOP(operation = OPERATION_USER,operaType = LogType.UPDATE)
    @PutMapping("update")
    public R update(@RequestBody UserDTO dto){
        userService.update(dto);
        return R.ok("修改成功");
    }

    @MyLogsAOP(operation = OPERATION_USER,operaType = LogType.RESET)
    @PutMapping("resetPwd")
    public R resetPwd(@RequestBody ResetPwdDTO dto){
        userService.resetPwd(dto);
        return R.ok("重置密码成功");
    }

    @MyLogsAOP(operation = OPERATION_USER,operaType = LogType.DELETE)
    @DeleteMapping("delete/{id}")
    public R delete(@PathVariable Integer id){
//        userService.delete(id);
        userService.removeById(id);
        return R.ok("删除成功");
    }

    @MyLogsAOP(operation = OPERATION_USER,operaType = LogType.BATCH_DELETE)
    @DeleteMapping("deleteBatch")
    public R deleteBatch(@RequestBody List<Integer> ids){
//        userService.deleteBatch(ids);
        userService.removeBatchByIds(ids);
        return R.ok("批量删除成功");
    }

    @GetMapping("findAll")
    public R findAll(){
//        return R.ok(userService.findAll());

//        QueryChainWrapper<User> query = userService.query();
//        User user = query.getEntity();

        List<User> list = userService.list(new QueryWrapper<User>().orderByDesc("id"));
        return R.ok(list);
    }

    @MyAuthAccess
    @GetMapping("findAll_test")
    public R findAll_test(){
//        return R.ok(userService.findAll());
        return R.ok(findAll());
    }

    @GetMapping("findById/{id}")
    public R findById(@PathVariable Integer id){
//        return R.ok(userService.findById(id));
        return R.ok(userService.getById(id));
    }

//    @GetMapping("findByName")
//    public R findById(@RequestParam String name){
//        return R.ok(userService.findByName(name));
//    }

//    @GetMapping("findByParam")
//    public R findByParam(@RequestParam String name){
//        return R.ok(userService.findByParam(name));
//    }

    @MyLogsAOP(operation = OPERATION_USER,operaType = LogType.LOOKUP)
    @GetMapping("findByPage")
    public R findByPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize,@RequestParam String username,@RequestParam String name){
       if (userService.updateAllComputerStatus()) {
           log.info("查询并更新电脑状态信息成功");
       }

//        Page<User> page = userService.findByPage(name, pageNum, pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(username),"username",username);
        queryWrapper.like(StrUtil.isNotBlank(name),"name",name);
        //构建page对象
        IPage<User> iPage = new Page<>(pageNum, pageSize);
        IPage<User> page = userService.page(iPage, queryWrapper);
        return R.ok(page);
    }

    /**
     * 批量导出数据
     * @param username
     * @param name
     * @param response
     */
    @MyLogsAOP(operation = OPERATION_USER,operaType = LogType.EXPORT_EXCEL)
    @GetMapping("/exportExcel")
    public void exportExcel(@RequestParam(required = false) String username,
                            @RequestParam(required = false) String name,
                            @RequestParam(required = false) String ids,
                            @RequestParam(required = false) String type,
                            HttpServletResponse response) throws IOException {
        boolean isTemplate = false;
        //类型为模板
        if (StrUtil.isNotBlank(type) && "template".equals(type)){
            isTemplate = true;
        }

        //设置响应类型格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(isTemplate?"三谷工具库-用户信息Excel模板":"三谷工具库-用户信息表","UTF-8")+".xlsx");//附件方式下载

        //获取写对象
        ExcelWriter writer = ExcelUtil.getWriter(true);
        //没有选中或全选==全部导出
        List<User> list;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        //类型为模板
        if (isTemplate){
            //应该从FileService调用
            String fullRootPath = fileService.download(0, "common", "三谷工具库-用户信息Excel模板.xlsx");
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(FileUtil.readBytes(fullRootPath));   //文件的字节流数组
            outputStream.flush(); //刷出去
            outputStream.close(); //关闭文件流
        }else {
            if (StrUtil.isNotBlank(ids)){
                //选择了多选框，其他条件不生效
                List<Integer> idsArr = Arrays.stream(ids.split(",")).map(Integer::valueOf).collect(Collectors.toList());
                queryWrapper.in("id",idsArr);
            }else {
                //没有选多选框，查询条件生效。当然逻辑上也可以提出去，任一条件生效即可。
                queryWrapper.like(StrUtil.isNotBlank(username),"username",username);
                queryWrapper.like(StrUtil.isNotBlank(name),"name",name);
            }
            list = userService.list(queryWrapper); //条件查询User表
            //        ExcelWriter write = writer.write(list, true);
            writer.write(list,true);

            //把响应输出流刷出去，同时关闭Out流
            ServletOutputStream stream = response.getOutputStream();
            writer.flush(stream,true);

            //保险起见，手动刷出去和手动关流
            writer.close();
            stream.flush();
            stream.close();
        }
    }

    @MyLogsAOP(operation = OPERATION_USER,operaType = LogType.IMPORT_EXCEL)
    @PostMapping("importExcel")
    public R importExcel(MultipartFile file) throws IOException {
        //读取文件输入流
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
        List<User> users = reader.readAll(User.class);
        boolean b;
        String msg = "导入失败，请重试或联系管理员";

        try {
            b = userService.saveBatch(users);
        } catch (Exception e) {
            Throwable cause = e.getCause();
            if (cause instanceof BatchUpdateException){
                throw new ServiceException("批量导入的用户信息中，有用户名可能已被使用！批量更新异常详情："+cause.getMessage());
            }else if(cause instanceof SQLIntegrityConstraintViolationException){
                throw new ServiceException("批量导入的用户信息中，有用户名已被使用");
            } else {
                throw new ServiceException("异常实例未适配到");
            }
        }
        return b ? R.ok() : R.fail(msg);
    }

    @GetMapping("getSelect")
    public R getSelect(){
        List<TreeDataDTO> list = userService.getSelect();
        return R.ok(list);
    }

    // 退出登录接口
    @PostMapping("/logout")
    public R logout(@RequestParam Integer userId) {
        userService.logout(userId);
        return R.ok("退出登录成功");
    }

    @MyLogsAOP(operation = OPERATION_USER, operaType = LogType.UPDATE)
    @PutMapping("updateComputerStatus")
    public R updateComputerStatus(@RequestBody Map<String, Object> params) {
        try {
            Integer id = (Integer) params.get("id");
            Integer computer = (Integer) params.get("computer");
            // 调用服务层更新电脑状态
            boolean result = userService.updateComputerStatus(id, computer);
            if (result) {
                return R.ok("电脑状态更新成功");
            } else {
                return R.fail("电脑状态更新失败");
            }
        } catch (Exception e) {
            throw new ServiceException("更新电脑状态时发生错误");
        }
    }
}
